module StochasticSimulation.Main

open System
open System.Diagnostics
open StochasticSimulation.Simulator
open StochasticSimulation.ChemicalReaction.ChemicalSpecies
open StochasticSimulation.ChemicalReaction.ChemicalReaction

// TODO : parse these from reader input, possibly a DSL eventually
let InitialiseSystem = 
        [ {Species = { Name ="I" } ; Count = 0 };
        {Species = { Name ="S" } ; Count =  1 };
        {Species = { Name ="P" } ; Count = 100 } ] :> seq<SpeciesCount>

let reactions = [|
        { Rate = 10000.0 ; Changes = dict[ {Name = "I"}, {Destroyed =0 ; Created=1}] };
        { Rate = 1000.0 ; Changes = dict[ {Name = "I"}, {Destroyed =1 ; Created=0} ; {Name = "P"}, {Destroyed =0 ; Created=1} ] };
        { Rate = 1.0 ; Changes = dict[ {Name = "P"}, {Destroyed =1 ; Created=0}] };
        { Rate = 9900.0 ; Changes = dict[ {Name = "I"}, {Destroyed =1 ; Created=0} ; {Name = "S"}, {Destroyed =1 ; Created=1} ] };
        { Rate = 10000.0 ; Changes = dict[ {Name = "S"}, {Destroyed =0 ; Created=1}] };
        { Rate = 1000.0 ; Changes = dict[ {Name = "S"}, {Destroyed =1 ; Created=0}] }  
        |]
    
let chosenStrategy = "Gillespie"

let writeSystem t (system:SpeciesCount list) =
    printf "%f " t
    system |> Seq.iter ( fun s -> printf " %A %d " s.Species.Name s.Count )
    printf "\n"

let updateReceived =
    new ProgressUpdateDelegate( fun sender args -> writeSystem args.Time args.Latest )

let SAMPLE_SIZE = 1

[<EntryPoint>]
let main (args : string[]) =
    let simulator = new Simulator(InitialiseSystem, reactions)

    simulator.OnProgress.AddHandler( updateReceived )

    let reactionAlgorithm = simulator.getAlgorithm chosenStrategy  // move to simulator
    
    let stopWatch = new Stopwatch()
    stopWatch.Start()

    let counts = seq {
      for i = 1 to SAMPLE_SIZE do 
        stopWatch.Restart()
        let result = simulator.ExecuteReaction reactionAlgorithm DateTime.Now.Millisecond 5.0
        result |> Seq.iter ( fun s -> printf " %A %d " s.Species.Name s.Count )
        printf "(%d milliseconds)\n" stopWatch.ElapsedMilliseconds
        yield result |> Seq.filter (fun f -> f.Species.Name = "P" ) |> Seq.map (fun s -> (float)s.Count) |>  Seq.sum   
    }

    printf "averageS count: %f" ( counts |> Seq.average )
    0